#include <gtest/gtest.h>

#include <functional> // std::reference_wrapper, std::ref(), std::cref()
#include <utility>
#include <optional>
#include <memory>
#include <tuple>

class PObj {
public:
	PObj() :_i(0) {
		std::cout <<"default ctor" << std::endl;
	}
	PObj(const PObj & other) {
		_i = other._i;
		std::cout <<" ctor(constT&)" << std::endl;
	}
	PObj(PObj && other) {
		_i = other._i;
		other._i = 0;
		std::cout << "ctor(T &&)" << std::endl;
	}

	PObj & operator=(const PObj & other) {
		std::cout << "operator=(const T&)" << std::endl;
		_i = other._i;
		return *this;
	}
	PObj & operator=(PObj && other) {
		std::cout << "operator=(T &&)" << std::endl;
		_i = other._i;
		other._i = 0;
		return *this;
	}

	const int get() const {
		return _i;
	}
private:
		int _i;
};

//"default-ctor"
static PObj createPObj(){
	return PObj();
}
//"default-ctor"
static std::unique_ptr<PObj> createUniquePtr(){
	return std::make_unique<PObj>();
	//return std::unique_ptr<PObj>(new PObj);
}
//"default-ctor"
static std::optional<PObj> createOptionalPObj(){
	return std::make_optional<PObj>();
}

// PObj-ctor &&   move the obj to pair's member
//"default-ctor" && "ctor(T&&)"
static std::pair<PObj, std::error_code> createPairPObj(){
	return std::make_pair(PObj(), std::error_code());
}
//"default-ctor" && "ctor(T&&)"
static std::tuple<PObj, std::error_code> createTuplePObj(){
	return {PObj(), std::error_code()};
}
//"default-ctor" && "ctor(T&&)"
static std::tuple<PObj, std::error_code> createTuplePObj_make(){
	return std::make_tuple(PObj(), std::error_code());
}

TEST(ConstructorTest, functionRetObject){

	createPObj();

	createUniquePtr();

	createOptionalPObj();

	{
		auto && [obj, ec] = createPairPObj();
		ASSERT_EQ(std::error_code(), ec);
	}

	{	
		auto && [obj, ec] = createTuplePObj();
		ASSERT_EQ(std::error_code(), ec);
	}
	{	
		auto && [obj, ec] = createTuplePObj_make();
		ASSERT_EQ(std::error_code(), ec);
	}
}
